#ifndef MYMAP_H
#define MYMAP_H

#include "json.hpp"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QObject>
#include <QGraphicsItem>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QScrollBar>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>

using json = nlohmann::json;

class visibleNode;

//节点类
class myNode {
private:
    int m_ID;               //节点ID
    std::string m_name;     //名称
    std::string m_address;  //地址
    double m_x;             //横轴坐标
    double m_y;             //纵轴坐标
    std::string m_tag;      //分类
    std::string m_label;    //标签（分类和标签没什么太大区别，都可以用作检索的词条）
    double m_rating;        //平均评分
    double m_rateNum;       //评分数
    int m_hot;              //热度
    visibleNode* m_vptr;    //指向可视化节点的指针
    std::vector<int> m_adjNode;   //相邻节点的ID列表

public:
    //写入JSON
    void toJson(json& j) const;
    void toJsonInner(json& j)const;
    //读取JSON
    void fromJson(const json& j);
    void fromJsonInner(const json& j);
    //以下函数用于获取相应信息
    int getID() const;
    std::string getName() const;
    std::string getAddress() const;
    double getX() const;
    double getY() const;
    std::string getTag() const;
    std::string getLabel() const;
    double getRating() const;
    double getRateNum() const;
    int getHot() const;
    visibleNode* getPtr() const;
    std::vector<int>& getAdjNode();
    //以下函数用于更改相应信息
    void setID(const int ID);
    void setPtr(visibleNode* ptr);
    void addAdjNode(int node);
    void init(int ID, std::string& name, double x, double y);    //调试用
};

//地图类，管理各节点信息
class myMap : public QObject
{
    Q_OBJECT
private:
    const int m_type;
    std::unordered_map<int, myNode> m_nodeList;   //存放节点信息（节点ID->节点信息）
    const std::string m_fileName;
    std::unordered_map<std::string, int> m_nameToID;    //节点名称->节点ID
    std::vector<std::string> m_nameList;               //存放节点名称
    int m_nodeNum = 100;
    std::vector<std::vector<bool>> m_pathMap;
    std::vector<int> m_visitingNode;

public:
    static const int FullType = 0, InnerType = 1, testType = 2;   //决定myMap初始化为大地图还是某个地点的内部地图
    myMap(const int type, const std::string fileName);
    ~myMap();
    //获取节点名称列表
    std::vector<std::string>& getNameList();
    //获取所有节点信息
    std::unordered_map<int, myNode>& getAllNodeInfo();
    //获取对应节点信息（根据名称）
    myNode& getNodeInfoName(const std::string& name);
    //获取对应节点信息（根据ID）
    myNode& getNodeInfoID(const int ID);
    //获取道路连通信息
    std::vector<std::vector<bool>>& getPathInfo();
    //添加待参观地点
    void addVisitingNode(const int ID);
    //移除待参观地点
    void removeVisitingNode(const int ID);
    //检查待参观景点队列的状态，0为空，1为满，2为已存在，3为可插入
    int checkVisitingNode(const int ID);
    //生成道路（调试用）
    void generatePath();
    //添加节点（调试用）
    void addNode(myNode* node);
    void addAdjNode(int ID, int adjNode);

private:
    //读取地图信息文件
    void loadMap();
    //保存地图信息文件
    void saveMap();

signals:

public slots:
    void makePath(myNode *node);

private:
    myNode* nodePtr = NULL;
};

class visibleCircle : public QGraphicsObject {
    Q_OBJECT
private:
    double m_size; //圆大小

public:
    explicit visibleCircle(qreal size, QGraphicsItem *parent = nullptr);
    QRectF boundingRect() const override;   //父类的虚函数
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;    //父类的虚函数

signals:
    void selected();    //选中节点时触发的信号，该信号使visibleNode再发出selected信号传出myNode*参数
    void makePath();    //调试用，右键选中两个节点可增加或删除道路

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override;     //重写该函数实现选中节点时发送信号的功能

};

//可视化节点
class visibleNode : public QObject {
    Q_OBJECT
private:
    visibleCircle *m_circle;
    double m_x;
    double m_y;
    double m_size;      //可视化节点的大小
    myNode* m_nptr;     //指向信息节点的指针

public:
    explicit visibleNode(qreal x, qreal y, qreal size, QObject *parent = nullptr);
    visibleCircle *getCircle() const;
    double getX() const;
    double getY() const;
    void setPtr(myNode *node);
    myNode *getPtr() const;

signals:
    void selected(myNode *node);    //选中节点时触发的信号
    void makePath(myNode *node);    //调试用，右键选中两个节点可增加或删除道路


};

class visiblePath : public QGraphicsObject {
    Q_OBJECT
private:
    //道路连接的两点
    QPointF m_p1;
    QPointF m_p2;
    QPainterPath m_shape;   //定义精准的碰撞区域

public:
    explicit visiblePath(myNode *p1, myNode *p2, QGraphicsItem *parent = nullptr);
    QRectF boundingRect() const override;   //父类的虚函数
    QPainterPath shape() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;    //父类的虚函数
    //使绘制的道路不响应鼠标事件
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override {event->ignore();}
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override {event->ignore();}
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override {event->ignore();}


};

//自定义的可交互视图（用于地图的拖拽移动视角以及滚轮缩放）
class myView : public QGraphicsView {
    Q_OBJECT
private:
    QPoint m_lastMousePos;      //记录鼠标指针位置
    QGraphicsItem *curNode = nullptr;     //目前选中的节点

public:
    myView(QWidget *parent = nullptr);
    //绘制节点
    void drawNode(myMap *map);
    //绘制道路
    void drawPath(myMap *map);

protected:
    //滚轮缩放
    void wheelEvent(QWheelEvent *event) override;
    //下面三个函数实现鼠标拖拽移动视角
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

signals:
    void selected(myNode *node);    //选中节点时触发的信号
    void makePath(myNode *node);    //调试添加道路用
public slots:
    void SmakePath(myNode *node);   //调试添加道路用
};

#endif // MYMAP_H
